﻿#region Imports
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using BulkRenamer.App.Main;
using BulkRenamer.Common.ResourceFiles;
using BulkRenamer.Common.Models;
using BulkRenamer.Util.Enums;
using CommonUtilities.Extensions;
using CommonUtilities.Messages;
using CommonUtilities.Util;
#endregion

namespace BulkRenamer.App.Views
{
    public partial class frmGridPreview : Form
    {
        #region Declarations
        Dictionary<string, int> dictWidth = new Dictionary<string, int>();

        /// <summary>
        /// Stores file Id-CustomName mapping to identify org value as NOT changed if reverted after intermediate changes
        /// </summary>
        Dictionary<int, string> dictIdCustNameMap = new Dictionary<int, string>();

        List<string> ignoreCols = new List<string>();

        /// <summary>
        /// Last property name to have been applied sort
        /// </summary>
        string propNameLast = "";

        /// <summary>
        /// Column sort identifer during toggling on same column
        /// </summary>
        bool isSortAscending = false;

        /// <summary>
        /// BackColor to be displayed when cell value is changed
        /// </summary>
        Color colCellEdited = Color.PeachPuff;

        /// <summary>
        /// BackColor to be displayed when cell value is reverted after intermediate changes
        /// </summary>
        Color colCellReverted = Color.Thistle;
        #endregion

        #region Properties
        public bool HasAlignedManually { get; set; }

        private readonly ObservableCollection<FileDetails> org = null;
        private ObservableCollection<FileDetails> AllFileDetails_org { get { return org; } }

        public ObservableCollection<FileDetails> AllFileDetails_mod { get; set; }

        public bool IsPreviewOnly { get; set; }
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes form
        /// </summary>
        /// <param name="allFileDetails">Original file details (read-only)</param>
        /// <param name="isPreviewOnly">TRUE: Preview in read-only mode</param>
        public frmGridPreview(ObservableCollection<FileDetails> allFileDetails, bool isPreviewOnly)
        {
            InitializeComponent();
            DialogResult = DialogResult.Cancel;

            IsPreviewOnly = isPreviewOnly;
            org = allFileDetails; // Keep original collection as backup
            dgFilePreview.DataSource = new ObservableCollection<FileDetails>(
                Utilities.CopyValues<FileDetails>(AllFileDetails_org)); // Create copy and assign as source

            // REQ-##164 : Custom Name if reverted to org value after intermediate changes should not mark item as changed
            AllFileDetails_org._ForEach(fdet => dictIdCustNameMap.AddToDictionary(fdet.FileId, fdet.NameCustom));

            List<DataGridViewColumn> cols = dgFilePreview.Columns.Cast<DataGridViewColumn>().ToList();
            cols.Where(c => c.Visible).ForEach(col => dictWidth.Add(col.Name, col.Width));

            ignoreCols.Add(colNameSugg.Name);
            ignoreCols.Add(colNameCust.Name);

            if (IsPreviewOnly)
            {
                dgFilePreview.ReadOnly = true;
                colNameSugg.Visible = colTakeSuggested.Visible = false;
                this.Width = this.Width * 2 / 3;
                btnExit.Location = btnSaveExit.Location;
                btnSaveExit.Visible = false;
                this.CancelButton = this.AcceptButton = btnExit;
            }
        }
        #endregion

        #region Destructors
        ~frmGridPreview()
        {
            this.Dispose();
            GC.Collect();
        }
        #endregion

        #region Events
        private void btnExit_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
            this.Close();
        }

        private void dgFilePreview_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
        {
            eAllowance allowance = eAllowance.None;
            string dcName = e.Column.Name;

            switch (dcName)
            {
                case "TakeSuggestion":
                    allowance = eAllowance.None;
                    break;
                default:
                    allowance = eAllowance.More;
                    break;
            }

            SetColumnWidth(dcName, allowance);
        }

        private void dgFilePreview_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex != -1)
            {
                DataGridViewRow drEdited = dgFilePreview.Rows[e.RowIndex];
                int id = (int)drEdited.Cells[colFileId.Name].Value;
                FileDetails fd = AllFileDetails_org.Where(fdet => fdet.FileId == id).FirstOrDefault();

                if (!fd.IsNull())
                {
                    if (!btnSaveExit.Enabled) btnSaveExit.Enabled = ValidateSaveExit(); // dgFilePreview.IsCurrentRowDirty;

                    string editedName = (string)drEdited.Cells[colNameCust.Name].Value;
                    bool editedTakeSuggested = (bool)drEdited.Cells[colTakeSuggested.Name].Value;

                    if (fd.NameCustom != editedName || fd.TakeSuggested != editedTakeSuggested)
                    {
                        drEdited.Cells[colNameCust.Name].Style.BackColor = (editedName != dictIdCustNameMap[id]) ? colCellEdited : colCellReverted;
                        drEdited.Cells[colTakeSuggested.Name].Style.BackColor = (editedTakeSuggested != fd.TakeSuggested) ? colCellEdited : SystemColors.Window;

                        btnSaveExit.Enabled = true;
                        if (dgFilePreview.Columns[e.ColumnIndex].Name == colNameCust.Name)
                            drEdited.Cells[colTakeSuggested.Name].Value = (editedName == dictIdCustNameMap[id]);
                    }
                }
            }
        }

        private void btnSaveExit_Click(object sender, EventArgs e)
        {
            if (MessageBoxUtil.Show(Program.IsDebug, "Do you really want to save these file details?", "Confirmation..", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                AllFileDetails_mod = (ObservableCollection<FileDetails>)dgFilePreview.DataSource;
                DialogResult = DialogResult.OK;
                this.Close();
            }
            else
                btnExit_Click(sender, e);
        }

        private void frmGridPreview_Activated(object sender, EventArgs e)
        {
            //this.Opacity = 1; // RKD
        }

        private void frmGridPreview_Deactivate(object sender, EventArgs e)
        {
            //this.Opacity = 0.8; // RKD
        }

        private void Resize_Columns(object sender, EventArgs e)
        {
            dgFilePreview.Width = this.Width - 6;
            SetColumnWidth("colNameSugg", eAllowance.AllowResize);
            SetColumnWidth("colNameCust", eAllowance.AllowResize);
            SetColumnWidth("colNameSugg", eAllowance.More);
            SetColumnWidth("colNameCust", eAllowance.More);
        }

        private void dgFilePreview_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if (dgFilePreview.Columns[e.ColumnIndex].Name == colNameCust.Name)
            {
                ObservableCollection<FileDetails> validFiles = (ObservableCollection<FileDetails>)dgFilePreview.DataSource;
                ObservableCollection<string> errMsgs = new ObservableCollection<string>();

                lblErrors.Text = "No errors"; lblErrors.ForeColor = Color.Green;
                int id = Convert.ToInt32(dgFilePreview.Rows[e.RowIndex].Cells[colFileId.Name].Value);
                string org = Convert.ToString(dgFilePreview.Rows[e.RowIndex].Cells[colNameCust.Name].Value);
                string formatted = Convert.ToString(e.FormattedValue);
                string extn = Convert.ToString(dgFilePreview.Rows[e.RowIndex].Cells[colFileExtn.Name].Value);

                ObservableCollection<FileDetails> dupes = validFiles.Where(fdet => fdet.FileId != id && fdet.FileExtn == extn
                    && !fdet.NameCustom.IsNullOrEmpty() && fdet.NameCustom == formatted).ToObservableCollection();
                ObservableCollection<object> errorIds = dupes._Select(fdet => fdet.FileId).AddItem(id)
                    ._OrderBy(fileid => fileid)._Cast<object>().ToObservableCollection();

                if (e.FormattedValue.ToString().IsNullOrEmpty()) errMsgs.Add("Name cannot be blank"); // Blank file name
                else if (dupes.Any()) // Different row having same extn, cannot have same file name
                    errMsgs.Add(ResourceBulkRenamer.Err_Preview_Dupes.FormatTextFromParams(errorIds.AppendText(", "), id)); // List all IDs

                if (errMsgs.Any())
                {
                    string sError = "";
                    sError = errMsgs.AppendText(Utilities.cNewLine);
                    sError = sError.TrimEnd(Utilities.cNewLine.ToCharArray());
                    dgFilePreview.Rows[e.RowIndex].ErrorText = sError;
                    lblErrors.Text = sError.Replace(Utilities.cNewLine, "; ") + "...";
                    lblErrors.ForeColor = Color.Red;

                    // Restrict
                    dgFilePreview.Rows[e.RowIndex].Cells[colNameCust.Name].Value = org;
                    e.Cancel = true;
                }
            }

            lblErrors.Visible = true;
        }

        private void dgFilePreview_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            DataGridViewColumn dgCol = dgFilePreview.Columns[e.ColumnIndex];
            if (dgCol.SortMode == DataGridViewColumnSortMode.NotSortable) return;

            string propName = dgCol.DataPropertyName;
            bool sortDirection = true;

            if (propNameLast.IsBlank()) // First time sort
            {
                sortDirection = (propName != colFileId.DataPropertyName); // Sort descending if FileId field; else ascending
                isSortAscending = false;
            }
            else // Next sort onwards
            {
                if (propName == propNameLast) isSortAscending = !isSortAscending;  // Toggle sort direction if on same property
                else if (propName != propNameLast) isSortAscending = true; // Sort ascending if new property

                sortDirection = isSortAscending;
            }

            dgFilePreview.DataSource = ((ObservableCollection<FileDetails>)dgFilePreview.DataSource).OrderByProperty(propName, sortDirection).ToObservableCollection();
            propNameLast = propName;
        }
        #endregion Events

        #region Methods
        private void SetColumnWidth(string colName, eAllowance allowance)
        {
            if (dgFilePreview.Columns.Contains(colName))
            {
                DataGridViewColumn dc = dgFilePreview.Columns[colName];
                int width = 0;

                switch (colName)
                {
                    case "colNameSugg":
                    case "colNameCust":
                        if (!HasAlignedManually)
                        {
                            int rem = dgFilePreview.Width - dictWidth.Where(col => !ignoreCols.Contains(col.Key)).Select(col => col.Value).Sum() - 20;
                            width = rem / 2;
                        }
                        break;
                    default:
                        if (dictWidth.ContainsKey(colName)) width = dictWidth[colName];
                        break;
                }

                if (allowance == eAllowance.AllowResize || allowance == eAllowance.None || (allowance == eAllowance.Less & dc.Width > width) || (allowance == eAllowance.More & dc.Width < width))
                    dc.Width = width;
            }
        }

        private bool ValidateSaveExit()
        {
            foreach (DataGridViewRow dr in dgFilePreview.Rows)
            {
                if (dictIdCustNameMap[Convert.ToInt32(dr.Cells[colFileId.Name].Value)] != Convert.ToString(dr.Cells[colNameCust.Name]))
                {
                    btnSaveExit.Enabled = false;
                    return false;
                }
            }

            return true;
        }
        #endregion Methods
    }
}
